﻿using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

[XLua.LuaCallCSharp]
public class AssetManager : MonoSingleton<AssetManager>
{
    public bool inited = false;
    public LoadMode loadMode;
    private List<AssetBundle> loadedBundles = new List<AssetBundle>();//已经加载的ab包
    private Dictionary<string, string> map;
    private string persistentDataPath_ab;
    private AssetBundleManifest manifestMain;

    public static T LoadAsset<T>(string assetPath) where T : UnityEngine.Object
    {
        return instance.Load<T>(assetPath);
    }

    public new void Init()
    {
        print("资源管理器初始化");
#if UNITY_EDITOR
        string loadModeStr = UnityEditor.EditorPrefs.GetString("AssetManager.LoadMode", "runTime");
        loadMode = loadModeStr == "editor" ? LoadMode.editor : LoadMode.runTime;
#else
        loadMode=LoadMode.runTime;
# endif
        inited = true;
    }

    /// <summary>
    /// 加载资源映射表,返回值表示map.json文件是否存在,可以用这个来判断是否是第一次运行游戏
    /// </summary>
    /// <returns></returns>
    public bool LoadAssetMap()
    {
        print("加载资源映射表");
        //加载资源映射表
        persistentDataPath_ab = Path.Combine(Application.persistentDataPath, "AB");
        string assetMapPath = Path.Combine(persistentDataPath_ab, "map.json");
        if (!File.Exists(assetMapPath))
        {
            return false;
        }
        string mapJosn = File.ReadAllText(assetMapPath);
        map = LitJson.JsonMapper.ToObject<Dictionary<string, string>>(mapJosn);
        return true;
    }

    public UnityEngine.Sprite LoadSprite(string assetPath)
    {
        return Load<Sprite>(assetPath);
    }

    public UnityEngine.Object Load(string assetPath)
    {
        return Load<UnityEngine.Object>(assetPath);
    }

    public T Load<T>(string assetPath) where T : UnityEngine.Object
    {
#if UNITY_EDITOR
        if (loadMode == LoadMode.editor)
        {
            return UnityEditor.AssetDatabase.LoadAssetAtPath<T>(assetPath);//从编辑器加载资源
        }
#endif
        return LoadFormAssetBundle<T>(assetPath);//从ab包加载资源
    }

    private T LoadFormAssetBundle<T>(string assetPath) where T : UnityEngine.Object
    {
        //从映射表查找assetPath对应的资源在哪个ab包中,映射表是我们在打ab包的时候生成的一个表[资源路径---ab包名称]
        print("DicKey:" + assetPath);
        string bundleName = map[assetPath];

        return LoadAsset<T>(bundleName, assetPath);
    }

    private T LoadAsset<T>(string bundleName, string assetName) where T : UnityEngine.Object
    {
        /////////////////////////////////////////////////////////////////////加载依赖/////////////////////////////////////////////////////////////////////
        string abMainName = AssetBundleDirName;

        //从主包加载清单
        if (manifestMain == null)
        {  //加载主包
            AssetBundle abMain = AssetBundle.LoadFromFile(Path.Combine(persistentDataPath_ab, abMainName));
            manifestMain = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }

        Debug.Log(bundleName);
        //用清单查询prefab包的依赖
        string[] dependens = manifestMain.GetAllDependencies(bundleName);

        for (int i = 0; i < dependens.Length; i++)
        {
            LoadAbBundle(dependens[i]);
        }
        /////////////////////////////////////////////////////////////////////加载依赖End/////////////////////////////////////////////////////////////////////
        //加载资源包
        AssetBundle ab = LoadAbBundle(bundleName);
        if (assetName.EndsWith(".unity")) return null; //场景不能使用LoadAsset,只要包在内存中就可以了
        //加载资源
        return ab.LoadAsset(assetName) as T;
    }

    private AssetBundle LoadAbBundle(string bundleName)
    {
        //////////////看一下是否被加载过,如果是就返回已经加载的ab包///////////////
        for (int i = 0; i < loadedBundles.Count; i++)
        {
            if (loadedBundles[i] == null) continue;
            if (loadedBundles[i].name == bundleName)
            {
                return loadedBundles[i];
            }
        }
        ////////////////////如果上面的代码没有返回说明这个包没有被加载过/////////////////////////////
        AssetBundle ab = AssetBundle.LoadFromFile(Path.Combine(persistentDataPath_ab, bundleName));
        loadedBundles.Add(ab);
        return ab;
    }

    public void UnLoadAssetBundle(string bundleName, bool unloadAsset)
    {
        for (int i = 0; i < loadedBundles.Count; i++)
        {
            if (loadedBundles[i].name == bundleName)
            {
                loadedBundles[i].Unload(unloadAsset);
                loadedBundles.RemoveAt(i);
                return;
            }
        }
    }

    public void UnLoadAllAssetBundle(Func<AssetBundle, bool> exclude = null, bool unloadAsset = true)
    {
        for (int i = loadedBundles.Count - 1; i >= 0; i--)
        {
            if (exclude == null || !exclude(loadedBundles[i]))
            {
                loadedBundles[i].Unload(unloadAsset);
                loadedBundles.RemoveAt(i);
                return;
            }
        }
    }

    public static string AssetBundleDirName
    {
        get
        {
            string name = "";

            switch (Application.platform)
            {
                case RuntimePlatform.WindowsEditor:
                case RuntimePlatform.WindowsPlayer:
                    name = "Win64";
                    break;

                case RuntimePlatform.Android:
                    name = "Android";
                    break;

                case RuntimePlatform.IPhonePlayer:
                    name = "iOS";
                    break;
            }
            return name;
        }
    }
}

public enum LoadMode
{
    runTime,
    editor,
}